/*
 * RecursivePentamino.cpp
 *
 *  Created on: Jun 28, 2011
 *      Author: denis
 */

#define INITIAL_DEPTH 0
#define MAX_DEPTH 11
#define I_R_NUM 2

#define X_MIN 0
#define Y_MIN 0
#define X_MAX 10
#define Y_MAX 6
#define ALLOWED_BITS     0x0FFFFFFFFFFFFFFFLLU
#define LEFT_NULL_COLUMN  0x7FDFF7FDFF7FDFFLLU
#define RIGHT_NULL_COLUMN 0xFFBFEFFBFEFFBFELLU
#define TOP_NULL_ROW     0x003FFFFFFFFFFFFLLU
#define BOTTOM_NULL_ROW  0xFFFFFFFFFFFFC00LLU

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <cstdlib>
#include <fstream>
#include <omp.h>

#include "init_pent.h"
#include "types.h"
#include "pent_low.h"
#include "recursion.h"

typedef std::ofstream* filelink;

using namespace std;

/*
int Recursion(Pentamino_Low * executor,int depth) {
		int l_depth=depth;
		unsigned long long current_position = 0;
		unsigned long long bit_intersection = 0;
	    unsigned long long default_current_position =0;
		longvector l_rotations;
		longvector::iterator rotation;

		l_rotations=*(executor->rot_depth(l_depth));
		int xsubs=0;
		int ysubs=0;

		int temp=0;
		//for (rotation = l_rotations.begin(); rotation!= l_rotations.end(); rotation++) {
		//std::cout<<depth<<';';
		for(int count=0;count<l_rotations.size();count++){
		temp++;

			default_current_position=l_rotations[count];
			xsubs=executor->xsubs(default_current_position);
			ysubs=executor->ysubs(default_current_position);
			executor->cur_fil_upd();
			for (int ycount = Y_MIN; ycount < Y_MAX-ysubs; ycount++) {
				current_position = (default_current_position >> ((X_MAX)* ycount));
				for (int xcount = X_MIN; xcount < X_MAX-xsubs; xcount++) {
					bit_intersection=current_position & (executor->current_field_status);
					if ((bit_intersection== 0)&&(executor->CheckRegions(current_position ^ executor->current_field_status))) {
						executor->iprevious_steps_array->push_back(current_position);
						if (l_depth == 11) {
							executor->printsolution();
							//executor->iprevious_steps_array->pop_back();
							executor->trim_to_depth(11);
							executor->cur_fil_upd();
						} else {
									Recursion(executor,l_depth+1);
									executor->trim_to_depth(l_depth);
									executor->cur_fil_upd();
									//executor->iprevious_steps_array->pop_back();
						}
					}
					current_position = (current_position >> 1)& LEFT_NULL_COLUMN;
				}
			}
		}
	return 0;
	};

*/
int ompver(){

	pentaminos_vector* rotations=Initialization();
	std::ofstream destfile1("/home/denis/pentamino_solutions_omp_1.txt");
	std::ofstream destfile2("/home/denis/pentamino_solutions_omp_2.txt");
	std::ofstream destfile3("/home/denis/pentamino_solutions_omp_3.txt");

	std::ofstream* temp;

	filelink destfile[3];

	destfile[0]=&destfile1;
	destfile[1]=&destfile2;
	destfile[2]=&destfile3;

	longvector* first_element=(*rotations)[0];
	unsigned long long g_current_position = 0;
	//unsigned long long g_bit_intersection = 0;
	unsigned long long g_default_current_position =0;


	g_default_current_position=(*first_element)[0];








				//#pragma omp parallel
	{
//#pragma omp for

					{


						for (int ycount = Y_MIN; ycount < 2; ycount++) {
								temp=(destfile[ycount]);
								g_current_position = (g_default_current_position >> ((X_MAX)* ycount));
								Row(g_current_position,rotations,temp);
							}


					}



	}
	//CLEANUP

		pentaminos_vector::iterator penvecit;
		for(penvecit=rotations->begin();penvecit!=rotations->end();penvecit++){
			(*penvecit)->clear();
			delete(*penvecit);
		}

		rotations->clear();
		delete(rotations);

	return 0;
}


/*

 This is python script used to generate initialization of vector of rotations

import string
import copy
from collections import deque

init_dict={'X':'403804000000000',
           'I':'802008020080000',
           'T':'E01004000000000',
           'U':'A03800000000000',
           'V':'80200E000000000',
           'W':'803006000000000',
           'Z':'C01006000000000',
           'L':'802008030000000',
           'N':'403008020000000',
           'P':'40300C000000000',
           'Y':'403004010000000',
           'F':'603004000000000'}


def IntToDD(intdd):
    bitstring=string.zfill(bin(intdd)[2:],60)
    separate=[bitstring[10*(i):10*(i+1)] for i in range(6)]
    dseparate=deque(separate)
    ddseparate=map(deque,dseparate)
    dddseparate=deque(ddseparate)
    return dddseparate

def HMirror(toproc):
    result=copy.deepcopy(toproc)
    map(deque.reverse,result)
    return result


def VMirror(toproc):
    result=copy.deepcopy(toproc)
    result.reverse()
    return result


def ScrollToTop(dd):
    result=copy.deepcopy(dd)
    while (tuple(result[0])==('0','0','0','0','0','0','0','0','0','0')):
        result.rotate(-1)
    return result

def ScrollToLeft(dd):
    result=copy.deepcopy(dd)
    flag= True;
    for element in result:
        flag=flag & (element[0]=='0')
    while (flag):
        for element in result:
            element.rotate(-1)
            flag=flag & (element[0]=='0')

    return result


def DDToInt(dd):
    result=copy.deepcopy(dd)
    longstring=""
    tempstring=""
    for el in range(6):
        tempstring=""
        longstring=longstring + tempstring.join(tuple(result[el]))
    return int(longstring,2)


def Transp5(in_deq):
    dddc=IntToDD(0)
    ld=map(list,dddc)
    inl=map(list,in_deq)
    for i in range(5):
        for j in range(5):
            ld[j][5-i]=inl[i][j]
    dl=map(deque,ld)
    ddl=deque(dl)
    return ddl


def norm(ddin):
    return ScrollToLeft(ScrollToTop(ddin))

def CreateRotations(int_rot):
    ddint_rot=IntToDD(int_rot)
    CSH=norm(HMirror(ddint_rot))
    CSV=norm(VMirror(ddint_rot))
    Ci=norm(HMirror(VMirror(ddint_rot)))
    C4=norm(Transp5(ddint_rot))
    CSHC4=norm(Transp5(CSH))
    CSVC4=norm(Transp5(CSV))
    CiC4=norm(Transp5(Ci))

    dd_rot_list=(ddint_rot,CSH,CSV,Ci,C4,CSHC4,CSVC4,CiC4)
    rot_list_int=map(DDToInt,dd_rot_list)
    rot_set=set(rot_list_int) # Deleting duplicating items
    return tuple(rot_set)

rotations_dict={};

for pent in init_dict.keys():
    print '#'+pent
    rotations_dict[pent]=CreateRotations(int(init_dict[pent],16))
    print "longvector "+ pent+';'
    for el in rotations_dict[pent]:
        print " "+pent+".push_back("+hex(el)+'LLU);'

*/


/*class PentaminoType // rewrite as STL iterator if there is such
{
	int current;
	int length;
	longvector * rotations_array;
public:
	PentaminoType() {
	}
	PentaminoType(longvector* rotations, int number_of_rotations) {
		length = number_of_rotations;
		current = 0;
		rotations_array = *rotations;
	}

	unsigned long long Next() {
		return rotations_array[current];
		current++;
	}
	bool isLast() {
		return current > length;
	}

};*/
